package cn.stazxr.core;

import cn.stazxr.config.CustomObjectMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.exceptions.JedisException;

import java.time.Duration;
import java.util.Set;

/**
 * @author talentestors
 * @version 1.0
 * @since 2025.10.28
 **/
@Component
@Slf4j
public class RedisTemplate {

	private final JedisPool jedisPool;
	private final CustomObjectMapper customObjectMapper;

	@Autowired
	public RedisTemplate(JedisPool jedisPool, CustomObjectMapper customObjectMapper) {
		this.jedisPool = jedisPool;
		this.customObjectMapper = customObjectMapper;
	}

	public Set<String> keys(String pattern) {
		try (Jedis jedis = jedisPool.getResource()) {
			return jedis.keys(pattern);
		} catch (Exception e) {
			log.error(e.getMessage());
			return Set.of();
		}
	}

	public long delete(String... key) {
		try (Jedis jedis = jedisPool.getResource()) {
			return jedis.del(key);
		} catch (JedisException e) {
			log.error("redis execution error in delete({}): {}", key, e.getMessage());
		}
		return 0;
	}

	/**
	 * Get value by key from Redis
	 *
	 * @param key Key
	 * @return Value
	 */
	public String get(String key) {
		try (Jedis jedis = jedisPool.getResource()) {
			return jedis.get(key);
		} catch (JedisException e) {
			log.error("redis execution error in get({}): {}", key, e.getMessage());
		}
		return null;
	}

	/**
	 * Set key-value pair in Redis
	 *
	 * @param key   Key
	 * @param value Value
	 * @return Status code reply
	 */
	public String set(String key, String value) {
		try (Jedis jedis = jedisPool.getResource()) {
			return jedis.set(key, value);
		} catch (JedisException e) {
			log.error("redis execution error: {} in set({}, {})", e.getMessage(), key, value);
		}
		return null;
	}

	public String set(String key, Duration duration, String value) {
		try (Jedis jedis = jedisPool.getResource()) {
			if (duration.getSeconds() <= 0) {
				log.warn("invalid expiration time in setex({}, {}, {}): {}", key, duration.getSeconds(), value, "seconds must be positive");
				return null;
			}
			return jedis.setex(key, duration.getSeconds(), value);
		} catch (JedisException e) {
			log.error("redis execution error: {} in setex({}, {}, {})", e.getMessage(), key, duration.getSeconds(), value);
		}
		return null;
	}

	// 将Redis的对象序列化
	public String setObject(String key, Object object) {
		try {
			String jsonString = customObjectMapper.writeValueAsString(object);
			return set(key, jsonString);
		} catch (Exception e) {
			log.error("serialization error in setObject({}, {}): {}", key, object, e.getMessage());
		}
		return null;
	}


	public String setObject(String key, Duration duration, Object object) {
		try {
			String jsonString = customObjectMapper.writeValueAsString(object);
			return set(key, duration, jsonString);
		} catch (Exception e) {
			log.error("serialization error in setObjectEx({}, {}, {}): {}", key, duration.getSeconds(), object, e.getMessage());
		}
		return null;
	}

	// reset ttl
	public long expire(String key, Duration duration) {
		try (Jedis jedis = jedisPool.getResource()) {
			return jedis.expire(key, duration.getSeconds());
		} catch (Exception e) {
			log.error("expire execution error: {} in set({}, {})", key, duration.getSeconds(), e.getMessage());
		}
		return 0L;
	}

	public <T> T getObject(String key, Class<T> clazz) {
		try {
			String jsonString = get(key);
			if (jsonString != null) {
				return customObjectMapper.readValue(jsonString, clazz);
			} else {
				return null;
			}
		} catch (JsonMappingException e) {
			log.error("deserialization error in getObject({}): {}", key, e.getMessage());
		} catch (JsonProcessingException e) {
			log.error("processing error in getObject({}): {}", key, e.getMessage());
		}
		return null;
	}

	public <T> T getObject(String key, TypeReference<T> refer) {
		try {
			String jsonString = get(key);
			if (jsonString != null) {
				return customObjectMapper.readValue(jsonString, refer);
			} else {
				return null;
			}
		} catch (JsonMappingException e) {
			log.error("deserialization error in getObject({}): {}", key, e.getMessage());
		} catch (JsonProcessingException e) {
			log.error("processing error in getObject({}): {}", key, e.getMessage());
		}
		return null;
	}


}
